/*
 * st7066u.c
 *
 * Created: 8/16/2013 3:12:06 PM
 *  Author: Ken Arok
 *
 * \file
 *
 * \brief Hardware Abstraction Layer of ST7066U LCD Controller.
 *
 * Copyright (c) 2013 PT Hanindo Automation Solutions. All rights reserved.
 *
 */

#include "config_board.h"

#if BOARD_1_0_USED

#if 1	/* Do not build if LCD controller is not ST6077U. */

#include "board.h"
#include "sysclk.h"
#include "gpio.h"
#include "delay.h"
#include "spi.h"
#include "st7066u.h"

/* LCD SPI characteristic options. */
static const spi_channel_options_t LCD_SPI_OPTIONS = {
	.baudrate = 4000000,	//!> 4 MHz clock frequency.
	.bits = 8,				//!> 8-bit data length.
	.delay_bs = 4,			//!> 4 x 30ns = 120ns TCES.
	.delay_bct = 5,			//!> 5 x 1us = 5us
	.keep_actv = 1,			//!> Drive CS logic manualy.
	.spi_mode = SPI_MODE_0,	//!> Mode 0 of SPI.
	.master_setup = true	//!> Setup in master mode.
};

static spi_descriptor_t spi_lcd_desc;

/** \brief Delay some cycle for LCD setup and hold waveform timing.
 *
 * \param _val	Value of delay cycle.
 *
 */
static void _delay_cycles(uint16_t _val)
{
	uint16_t _dummy;
	
	for(_dummy = 0; _dummy < _val; _dummy++);
}

/* -------------------------------------------------------------------------------------------------- */
void st7066u_send_data(const uint8_t _data)
{
	/* The waveform logic is opponent to instruction command.
	 * See Circuit diagram.
	 */
	gpio_set_pin_high(LCD_WR_RW_GPIO);
	gpio_set_pin_low(LCD_A0_RS_GPIO);

	while(SPI_STATUS_OK != spi_select_chip(spi_lcd_desc));
	spi_write_byte(spi_lcd_desc, (const void *)&_data, 1);
	while(SPI_STATUS_OK != spi_deselect_chip(spi_lcd_desc));

	_delay_cycles(10);
	gpio_set_pin_low(LCD_E_GPIO);
	_delay_cycles(30);
	gpio_set_pin_high(LCD_E_GPIO);
	delay_us(120);
}


void st7066u_send_instruction(const uint8_t _instr)
{
	/* The waveform logic is opponent to instruction command.
	 * See Circuit diagram.
	 */
	gpio_set_pin_high(LCD_WR_RW_GPIO);
	gpio_set_pin_high(LCD_A0_RS_GPIO);
	
	while(SPI_STATUS_OK != spi_select_chip(spi_lcd_desc));
	spi_write_byte(spi_lcd_desc, (const void *)&_instr, 1);
	while(SPI_STATUS_OK != spi_deselect_chip(spi_lcd_desc));

	_delay_cycles(10);
	gpio_set_pin_low(LCD_E_GPIO);
	_delay_cycles(30);
	gpio_set_pin_high(LCD_E_GPIO);
	delay_us(500);
}


void st7066u_init(void)
{
	const uint8_t txdata[5] = {0x30, 0x38, 0x0C, 0x01, 0x06};
	const char _spi_lcd_port[] = "SPILCD";

	/* Open SPI port. */
	spi_lcd_desc = spi_open(_spi_lcd_port, 0);
	if(spi_lcd_desc) {
		/* Delay >40ms */
		delay_ms(50);

		/* Setup SPI Interface for Monochrome LCD Display */
		if(SPI_STATUS_OK == spi_setup(spi_lcd_desc, &LCD_SPI_OPTIONS)) {
			/* Turn Back light On */
			gpio_set_pin_high(LCD_BLON_GPIO);

			/*! Function set: 8-bit; 2 lines; 5 x 7 dot */
			st7066u_send_instruction(txdata[1]);
			/*! Wait >37us */
			delay_us(40);
			st7066u_send_instruction(txdata[1]);
			/*! Wait >37us */
			delay_us(40);
			/*! Display ON */
			st7066u_send_instruction(txdata[2]);
			/*! Delay >37us */
			delay_us(40);
			/*! Display Clear */
			st7066u_send_instruction(txdata[3]);
			/*! Delay >1.52ms */
			delay_ms(2);
			/*! Entry Mode set: Increment, don't shift */
			st7066u_send_instruction(txdata[4]);
		}
	}
}


#endif

#endif /* BOARD_1_0_USED */
